package a05;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;

/**
 * 模拟ComponentScan的功能，实现一个BeanFactoryPostProcessor，用来扫描Component注解以及它的派生
 * 注解如@Controller
 */
public class MyComponentScanPostProcessor implements BeanFactoryPostProcessor {

    Logger logger = LoggerFactory.getLogger(MyComponentScanPostProcessor.class);

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        try {
            logger.debug("进入MyComponentScanPostProcessor...");
            BeanDefinitionRegistry registry = ((BeanDefinitionRegistry) beanFactory);

            ComponentScan annotation = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            if (annotation != null) {
                for (String path : annotation.basePackages()) {
                    String classPath = "classpath*:" + path.replace(".", "/") + "/**/*.class";
                    Resource[] resources = new PathMatchingResourcePatternResolver().getResources(classPath);
                    for (Resource resource : resources) {
                        MetadataReader metadataReader = factory.getMetadataReader(resource);
                        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
                        //Component和Component的派生注解，比如Controller。Controller里可以看到是有元注解Component
                        if (annotationMetadata.hasAnnotation(Component.class.getName())
                                || annotationMetadata.hasMetaAnnotation(Component.class.getName()) ) {
                            AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
                                    .genericBeanDefinition(metadataReader.getClassMetadata().getClassName()).getBeanDefinition();
                            registry.registerBeanDefinition(annotationMetadata.getClassName(), beanDefinition);
                        }
                    }
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
        }


    }
}
